// Pipeline Component Library Example
// ----------------------------------
// Colin Bowern (colinbowern@hotmail.com)
// January 2007
//
// Copyright (c) 2007 Colin Bowern
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * The above copyright notice and this permission notice shall be included in
//   all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#region References
using Microsoft.CommerceServer.Internal.Marketing;
using Microsoft.CommerceServer.Interop;
using Microsoft.CommerceServer.Interop.Caching;
using Microsoft.CommerceServer.Interop.Targeting;
using Microsoft.CommerceServer.Runtime;
using Microsoft.CommerceServer.Runtime.Caching;
using Microsoft.CommerceServer.Runtime.Configuration;
using Microsoft.CommerceServer.Runtime.Diagnostics;
using Microsoft.CommerceServer.Runtime.Orders;
using Microsoft.CommerceServer.Runtime.Pipelines;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Odbc;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
#endregion

namespace RockstarGuys.Pipelines.Tests
{
    internal static class Helper
    {
        #region Fields
        private static ICacheManager cacheManager;
        private static DebugContext debugContext;
        private static IExpressionEvaluator expressionEvaluator;
        private static IMessageManager messageManager;
        private static PipelineCollection pipelines;
        private static PipelineComponents.CommerceResources commerceResources;
        private static string siteName;
        #endregion

        #region Properties
        public static ICacheManager CacheManager
        {
            get
            {
                if (Helper.cacheManager == null)
                {
                    string runtimeAssemblyName = typeof(CommerceApplicationModule).Assembly.FullName;
                    string commerceCacheConfigTypeName = Assembly.CreateQualifiedName(runtimeAssemblyName, "Microsoft.CommerceServer.Runtime.Configuration.CommerceCacheConfig");
                    Type CommerceCacheConfig = Type.GetType(commerceCacheConfigTypeName);

                    object[] cacheManagerSection = (object[])ConfigurationManager.GetSection("CommerceServer/caches");

                    foreach (object cacheConfig in cacheManagerSection)
                    {
                        CommerceResource resource;
                        IDictionary cacheDictionary = (IDictionary)CommerceCacheConfig.GetProperty("CacheDictionary", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(cacheConfig, null);

                        CacheType type = (CacheType)(int)CommerceCacheConfig.GetProperty("Type", BindingFlags.Instance | BindingFlags.Public).GetValue(cacheConfig, null);
                        switch (type)
                        {
                            case CacheType.Advertising:
                                resource = CommerceResources.MarketingResource;
                                if (cacheDictionary["ConnectionString"] == DBNull.Value || cacheDictionary["ConnectionString"] == null)
                                {
                                    cacheDictionary["ConnectionString"] = CommerceResources.MarketingConnectionString;
                                }
                                cacheDictionary["Evaluator"] = Helper.ExpressionEvaluator;
                                break;

                            case CacheType.Discounts:
                                cacheDictionary["DefaultLanguage"] = CommerceResources.DefaultMarketingSystemLanguage;
                                goto case CacheType.Advertising;

                            case CacheType.MarketingDiscounts:
                                throw new NotImplementedException();

                            case CacheType.Shipping:
                                resource = CommerceResources.TransactionConfigResource;
                                if (cacheDictionary["ConnectionString"] == DBNull.Value || cacheDictionary["ConnectionString"] == null)
                                {
                                    cacheDictionary["ConnectionString"] = CommerceResources.TransactionConfigSqlConnectionString;
                                }
                                if (cacheDictionary["TableName"] == DBNull.Value || cacheDictionary["TableName"] == null)
                                {
                                    cacheDictionary["TableName"] = "txVirtual_Directory";
                                }
                                break;

                            case CacheType.OrdersConfiguration:
                                goto case CacheType.Shipping;

                            case CacheType.Payment:
                                goto case CacheType.Shipping;

                            default:
                                break;
                        }

                        string name = (string)CommerceCacheConfig.GetProperty("Name", BindingFlags.Instance | BindingFlags.Public).GetValue(cacheConfig, null);
                        int refreshInterval = (int)CommerceCacheConfig.GetProperty("RefreshInterval", BindingFlags.Instance | BindingFlags.Public).GetValue(cacheConfig, null);
                        int retryInterval = (int)CommerceCacheConfig.GetProperty("RetryInterval", BindingFlags.Instance | BindingFlags.Public).GetValue(cacheConfig, null);
                        string loaderProgId = (string)CommerceCacheConfig.GetProperty("LoaderProgID", BindingFlags.Instance | BindingFlags.Public).GetValue(cacheConfig, null);
                        string writerProgId = (string)CommerceCacheConfig.GetProperty("WriterProgID", BindingFlags.Instance | BindingFlags.Public).GetValue(cacheConfig, null);
                        string cacheObjectProgId = (string)CommerceCacheConfig.GetProperty("CacheObjectProgID", BindingFlags.Instance | BindingFlags.Public).GetValue(cacheConfig, null);
                        IDictionary loaderConfigDictionary = (IDictionary)CommerceCacheConfig.GetProperty("CacheDictionary", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(cacheConfig, null);
                        IDictionary writerConfigDictionary = (IDictionary)CommerceCacheConfig.GetProperty("CacheDictionary", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(cacheConfig, null);
                        DebugContext debugContext = Helper.DebugContext;
                        int cacheType = (int)type;

                        // Adds the cache to the underlying interop object which we'll grab later.
                        ConstructorInfo commerceCacheConstructor = typeof(CommerceCache).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
                        CommerceCache cache = (CommerceCache)commerceCacheConstructor.Invoke(new object[] { name, refreshInterval, retryInterval, loaderProgId, writerProgId, cacheObjectProgId, loaderConfigDictionary, writerConfigDictionary, debugContext, cacheType });
                    }

                    Helper.cacheManager = (ICacheManager)typeof(CommerceCache).GetProperty("InteropObject", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null);
                }
                return Helper.cacheManager;
            }
        }

        public static DebugContext DebugContext
        {
            get
            {
                if (Helper.debugContext == null)
                {
                    string runtimeAssemblyName = typeof(CommerceApplicationModule).Assembly.FullName;
                    string commerceApplicationConfigTypeName = Assembly.CreateQualifiedName(runtimeAssemblyName, "Microsoft.CommerceServer.Runtime.Configuration.CommerceApplicationConfig");
                    Type CommerceApplicationConfig = Type.GetType(commerceApplicationConfigTypeName);

                    object applicationSection = ConfigurationManager.GetSection("CommerceServer/application");

                    DebugMode debugMode = (DebugMode)CommerceApplicationConfig.GetProperty("DebugLevel", BindingFlags.Instance | BindingFlags.Public).GetValue(applicationSection, null);
                    Helper.debugContext = new ConsoleDebugContext(debugMode);
                }
                return Helper.debugContext;
            }
        }

        public static IExpressionEvaluator ExpressionEvaluator
        {
            get
            {
                if (Helper.expressionEvaluator == null)
                {
                    Helper.expressionEvaluator = new ExpressionEvaluator();
                    IExpressionStoreAdapter ExpressionStoreAdapter = new MarketingExpressionStoreAdapter(CommerceResources.MarketingSqlConnectionString);
                    Helper.expressionEvaluator.Connect(ExpressionStoreAdapter);
                }
                return Helper.expressionEvaluator;
            }
        }

        public static IMessageManager MessageManager
        {
            get
            {
                if (Helper.messageManager == null)
                {
                    string runtimeAssemblyName = typeof(CommerceApplicationModule).Assembly.FullName;
                    string commerceMessageManagerConfigTypeName = Assembly.CreateQualifiedName(runtimeAssemblyName, "Microsoft.CommerceServer.Runtime.Configuration.CommerceMessageManagerConfig");
                    Type CommerceMessageManagerConfig = Type.GetType(commerceMessageManagerConfigTypeName);

                    object messageManagerSection = ConfigurationManager.GetSection("CommerceServer/messageManager");

                    Helper.messageManager = (IMessageManager)CommerceMessageManagerConfig.GetProperty("MessageManager", BindingFlags.Instance | BindingFlags.Public).GetValue(messageManagerSection, null);
                }
                return Helper.messageManager;
            }
        }

        public static PipelineCollection Pipelines
        {
            get
            {
                if (Helper.pipelines == null)
                {
                    string runtimeAssemblyName = typeof(CommerceApplicationModule).Assembly.FullName;
                    string commercePipelineConfigTypeName = Assembly.CreateQualifiedName(runtimeAssemblyName, "Microsoft.CommerceServer.Runtime.Configuration.CommercePipelineConfig");
                    Type CommercePipelineConfig = Type.GetType(commercePipelineConfigTypeName);

                    object[] pipelineConfigurations= (object[])ConfigurationManager.GetSection("CommerceServer/pipelines");

                    Helper.pipelines = new PipelineCollection();
                    foreach (object pipelineConfiguration in pipelineConfigurations)
                    {
                        string pipelineName = (string)CommercePipelineConfig.GetProperty("Name", BindingFlags.Instance | BindingFlags.Public).GetValue(pipelineConfiguration, null);
                        string pipelineConfigPath = (string)CommercePipelineConfig.GetProperty("PCFPath", BindingFlags.Instance | BindingFlags.Public).GetValue(pipelineConfiguration, null);
                        bool loggingEnabled = (bool)CommercePipelineConfig.GetProperty("LoggingEnabled", BindingFlags.Instance | BindingFlags.Public).GetValue(pipelineConfiguration, null);
                        bool transactional = (bool)CommercePipelineConfig.GetProperty("TransactionalSetting", BindingFlags.Instance | BindingFlags.Public).GetValue(pipelineConfiguration, null);
                        string logPath = Path.Combine(Environment.CurrentDirectory, Path.GetFileNameWithoutExtension(pipelineConfigPath) + ".pipelog");
                        string pipelineType = CommercePipelineConfig.GetProperty("Type", BindingFlags.Instance | BindingFlags.Public).GetValue(pipelineConfiguration, null).ToString();

                        PipelineBase pipelineBase = null;
                        if (string.Compare(pipelineType, "OrderPipeline", true, CultureInfo.InvariantCulture) == 0)
                        {
                            pipelineBase = new Microsoft.CommerceServer.Runtime.Pipelines.OrderPipeline(pipelineName, pipelineConfigPath, loggingEnabled, logPath, transactional);
                        }
                        else if (string.Compare(pipelineType, "CSFPipeline", true, CultureInfo.InvariantCulture) == 0)
                        {
                            pipelineBase = new ContentSelectionPipeline(pipelineName, pipelineConfigPath, loggingEnabled, logPath);
                        }
                        else
                        {
                            throw new NotSupportedException("Pipeline type not supported - " + pipelineType);
                        }
                        Helper.pipelines.Add(pipelineName, pipelineBase);
                    }
                }
                return Helper.pipelines;
            }
        }

        public static PipelineComponents.CommerceResources CommerceResources
        {
            get
            {
                if (Helper.commerceResources == null)
                {
                    Helper.commerceResources = new PipelineComponents.CommerceResources(Helper.SiteName);
                }
                return Helper.commerceResources;
            }
        }

        public static string SiteName
        {
            get
            {
                if (Helper.siteName == null)
                {
                    string runtimeAssemblyName = typeof(CommerceApplicationModule).Assembly.FullName;
                    string commerceApplicationConfigTypeName = Assembly.CreateQualifiedName(runtimeAssemblyName, "Microsoft.CommerceServer.Runtime.Configuration.CommerceApplicationConfig");
                    Type CommerceApplicationConfig = Type.GetType(commerceApplicationConfigTypeName);

                    object applicationSection = ConfigurationManager.GetSection("CommerceServer/application");

                    Helper.siteName = (string)CommerceApplicationConfig.GetProperty("SiteName", BindingFlags.Instance | BindingFlags.Public).GetValue(applicationSection, null);
                }
                return Helper.siteName;
            }
        }
        #endregion

        #region Methods
        public static PipelineExecutionResult RunPipeline(OrderGroup orderGroup, string pipelineName, OrderPipelineType pipelineType)
        {
            PipelineBase pipeline = Helper.Pipelines[pipelineName];

            PipelineExecutionResult pipelineExecutionResult;
            using (PipelineInfo pipelineContext = new PipelineInfo(pipelineName, pipelineType))
            {
                pipelineContext[PipelineComponents.PipelineContext.KeyNames.CacheManager] = Helper.CacheManager;
                pipelineContext[PipelineComponents.PipelineContext.KeyNames.CommerceResources] = Helper.CommerceResources.CommerceResourceCollection;
                pipelineContext[PipelineComponents.PipelineContext.KeyNames.MessageManager] = Helper.MessageManager;
                pipelineContext[PipelineComponents.PipelineContext.KeyNames.TransactionConfigConnectionString] = Helper.CommerceResources.TransactionConfigConnectionString;

                pipelineExecutionResult = orderGroup.RunPipeline(pipelineContext, pipeline);
            }
            return pipelineExecutionResult;
        }
        #endregion

        #region Nested Types
        private enum CacheType
        {
            Advertising,
            Discounts,
            MarketingDiscounts,
            Shipping,
            Payment,
            OrdersConfiguration,
            Custom
        }
        #endregion
    }
}
